package util

import (
	"context"
	"regexp"
	"time"

	"go.uber.org/zap"
)

var (
	ValidBearer = regexp.MustCompile(`^[bB]earer (([a-zA-z0-9\-_]+\.){2}[a-zA-z0-9\-_]+)$`)
)

const (
	PageSizeKey  = "page_size"
	PageNoKey    = "page_no"
	TsKey        = "ts"
	RequestIDKey = "x-request-id"
	MockIDKey    = "x-mock-id"
)

// RequestID income requestID
type (
	RequestID struct{}

	BilinTokenKey struct{}
	// bilin token
	BilinToken struct {
		GID     string `json:"g_id"`
		BrandID int64  `json:"brand_id"`
		EmpID   int64  `json:"emp_id"`
		Name    string `json:"name"`
	}

	AuthorizationTokenKey struct{}
	// Authorization token (C端)
	AuthorizationToken struct {
		MemberID int64  `json:"member_id"`
		BrandID  int64  `json:"brand_id"`
		OpenID   string `json:"open_id"`
		AppID    string `json:"app_id"`
		BilinApp string `json:"bilin_app"` // mall_mina-商城微信小程序;bg_mina-星团小程序;mall_byte-商城抖音小程序;mall_alipay-商城支付宝小程序
	}

	PagerKey struct{}
	Pager    struct {
		Limit  int32
		Offset int32
		Ts     time.Time
	}

	ContextKey string
)

// NewContextLogger return SugaredLogger With ContextValue
func NewContextLogger(ctx context.Context, slog *zap.SugaredLogger) *zap.SugaredLogger {
	reqID := ctx.Value(RequestID{})
	return slog.With("reqID", reqID)
}

func GetReqID(ctx context.Context) interface{} {
	return ctx.Value(RequestID{})
}

func NewContext() context.Context {
	return context.Background()
}

func NewContextWithReqID(val interface{}) context.Context {
	return NewContextWithReqIDFrom(context.Background(), val)
}

func NewContextWithReqIDFrom(ctx context.Context, val interface{}) context.Context {
	return context.WithValue(ctx, RequestID{}, val)
}

func ParsePager(pageSizeStr, pageNoStr, tsStr string) (pagerPtr *Pager) {
	var limit, offset int32
	ts := time.Now()
	if IsEmpty(pageSizeStr) {
		pageSizeStr = "10"
	}
	limit = StringToInt32(pageSizeStr)
	if limit > 100 {
		limit = 100
	}

	if IsEmpty(pageNoStr) {
		pageNoStr = "1"
	}
	offset = (StringToInt32(pageNoStr) - 1) * limit

	if !IsEmpty(tsStr) {
		ms := StringToInt64(tsStr) / 1000
		// slog.Infof("ms=>%d", ms)
		ts = time.Unix(ms, 0)
		// slog.Infof("ts=>%s", util.GoTimeToString(ts))
	}

	pagerPtr = &Pager{
		Limit:  limit,
		Offset: offset,
		Ts:     ts,
	}
	return
}

func GetBilinToken(ctx context.Context) (token *BilinToken) {
	token = ctx.Value(BilinTokenKey{}).(*BilinToken)
	return
}

func GetAuthorizationToken(ctx context.Context) (token *AuthorizationToken) {
	token = ctx.Value(AuthorizationTokenKey{}).(*AuthorizationToken)
	return
}

func GetPager(ctx context.Context) (pager *Pager) {
	pager = ctx.Value(PagerKey{}).(*Pager)
	return
}

func ExtractToken(tokenRaw string) string {
	tokens := ValidBearer.FindStringSubmatch(tokenRaw)
	if len(tokens) != 3 {
		return tokenRaw
	}
	return tokens[1]
}
